"""
模式选择器

根据任务上下文和系统状态选择最适合的协调模式。
"""

from typing import Dict, List, Any, Optional, Tuple
from datetime import datetime, timedelta
from enum import Enum

from .coordination_patterns import (
    CoordinationMode, CoordinationContext, CoordinationPattern,
    select_coordination_mode
)


class SelectionCriteria(Enum):
    """选择标准"""
    URGENCY = "urgency"                 # 紧急程度
    COMPLEXITY = "complexity"           # 复杂度
    RESOURCE_AVAILABILITY = "resource"  # 资源可用性
    RISK_LEVEL = "risk"                # 风险等级
    STAKEHOLDER_COUNT = "stakeholder"   # 利益相关者数量
    HISTORICAL_PERFORMANCE = "history"  # 历史表现


class ModeSelector:
    """模式选择器"""
    
    def __init__(self):
        """初始化模式选择器"""
        # 模式选择规则
        self.selection_rules = self._initialize_selection_rules()
        
        # 模式性能历史
        self.mode_performance_history: Dict[CoordinationMode, Dict[str, Any]] = {
            mode: {
                "success_rate": 0.5,
                "average_duration": 3600.0,
                "usage_count": 0,
                "last_used": None,
                "failure_reasons": []
            }
            for mode in CoordinationMode
        }
        
        # 选择历史
        self.selection_history: List[Dict[str, Any]] = []
        
        # 配置参数
        self.config = {
            "performance_weight": 0.3,      # 历史性能权重
            "context_weight": 0.7,          # 上下文匹配权重
            "min_usage_threshold": 5,       # 最小使用次数阈值
            "performance_decay_factor": 0.9, # 性能衰减因子
            "selection_timeout": 30         # 选择超时时间（秒）
        }
    
    def select_mode(self, context: CoordinationContext) -> CoordinationMode:
        """
        选择协调模式
        
        Args:
            context: 协调上下文
            
        Returns:
            选择的协调模式
        """
        try:
            start_time = datetime.now()
            
            # 计算各模式的适合度分数
            mode_scores = self._calculate_mode_scores(context)
            
            # 选择得分最高的模式
            selected_mode = max(mode_scores, key=mode_scores.get)
            
            # 记录选择历史
            selection_record = {
                "timestamp": start_time,
                "context": context,
                "selected_mode": selected_mode,
                "mode_scores": mode_scores,
                "selection_duration": (datetime.now() - start_time).total_seconds()
            }
            self.selection_history.append(selection_record)
            
            # 更新使用统计
            self._update_usage_statistics(selected_mode)
            
            return selected_mode
            
        except Exception as e:
            # 返回默认模式
            return CoordinationMode.HIERARCHICAL
    
    def _calculate_mode_scores(self, context: CoordinationContext) -> Dict[CoordinationMode, float]:
        """计算各模式的适合度分数"""
        scores = {}
        
        for mode in CoordinationMode:
            # 基础上下文匹配分数
            context_score = self._calculate_context_score(mode, context)
            
            # 历史性能分数
            performance_score = self._calculate_performance_score(mode)
            
            # 综合分数
            total_score = (
                context_score * self.config["context_weight"] +
                performance_score * self.config["performance_weight"]
            )
            
            scores[mode] = total_score
        
        return scores
    
    def _calculate_context_score(self, mode: CoordinationMode, context: CoordinationContext) -> float:
        """计算上下文匹配分数"""
        score = 0.0
        
        # 获取模式的选择规则
        rules = self.selection_rules.get(mode, {})
        
        # 紧急程度匹配
        urgency_rules = rules.get("urgency", {})
        if context.urgency_level in urgency_rules:
            score += urgency_rules[context.urgency_level]
        
        # 复杂度匹配
        complexity_rules = rules.get("complexity", {})
        if context.complexity in complexity_rules:
            score += complexity_rules[context.complexity]
        
        # 任务类型匹配
        task_type_rules = rules.get("task_type", {})
        if context.task_type in task_type_rules:
            score += task_type_rules[context.task_type]
        
        # 参与者数量匹配
        participant_count = len(context.participants)
        participant_rules = rules.get("participant_count", {})
        for range_key, range_score in participant_rules.items():
            if self._is_in_range(participant_count, range_key):
                score += range_score
                break
        
        # 时间约束匹配
        time_constraint_rules = rules.get("time_constraints", {})
        if hasattr(context, 'time_constraints') and context.time_constraints:
            deadline = context.time_constraints.get("deadline")
            if deadline:
                time_pressure = self._calculate_time_pressure(deadline)
                for pressure_key, pressure_score in time_constraint_rules.items():
                    if self._is_in_range(time_pressure, pressure_key):
                        score += pressure_score
                        break
        
        # 资源约束匹配
        resource_rules = rules.get("resource_constraints", {})
        if hasattr(context, 'resource_constraints') and context.resource_constraints:
            resource_availability = self._calculate_resource_availability(context.resource_constraints)
            for availability_key, availability_score in resource_rules.items():
                if self._is_in_range(resource_availability, availability_key):
                    score += availability_score
                    break
        
        return min(score, 1.0)  # 限制在0-1范围内
    
    def _calculate_performance_score(self, mode: CoordinationMode) -> float:
        """计算历史性能分数"""
        performance = self.mode_performance_history[mode]
        
        # 如果使用次数不足，返回中等分数
        if performance["usage_count"] < self.config["min_usage_threshold"]:
            return 0.5
        
        # 基础成功率
        success_rate = performance["success_rate"]
        
        # 考虑时间衰减
        if performance["last_used"]:
            days_since_last_use = (datetime.now() - performance["last_used"]).days
            decay_factor = self.config["performance_decay_factor"] ** days_since_last_use
            success_rate *= decay_factor
        
        return success_rate
    
    def _initialize_selection_rules(self) -> Dict[CoordinationMode, Dict[str, Any]]:
        """初始化选择规则"""
        return {
            CoordinationMode.HIERARCHICAL: {
                "urgency": {"low": 0.8, "medium": 0.6, "high": 0.3, "critical": 0.1},
                "complexity": {"simple": 0.9, "moderate": 0.7, "complex": 0.4, "critical": 0.2},
                "task_type": {"decision": 0.9, "execution": 0.8, "monitoring": 0.7},
                "participant_count": {"1-3": 0.9, "4-6": 0.7, "7-10": 0.5, "10+": 0.3},
                "time_constraints": {"low": 0.8, "medium": 0.6, "high": 0.3},
                "resource_constraints": {"abundant": 0.8, "sufficient": 0.6, "limited": 0.4}
            },
            CoordinationMode.CONSENSUS: {
                "urgency": {"low": 0.9, "medium": 0.7, "high": 0.4, "critical": 0.1},
                "complexity": {"simple": 0.5, "moderate": 0.8, "complex": 0.9, "critical": 0.6},
                "task_type": {"decision": 0.9, "research": 0.8, "communication": 0.7},
                "participant_count": {"1-3": 0.3, "4-6": 0.8, "7-10": 0.9, "10+": 0.7},
                "time_constraints": {"low": 0.9, "medium": 0.7, "high": 0.3},
                "resource_constraints": {"abundant": 0.8, "sufficient": 0.7, "limited": 0.5}
            },
            CoordinationMode.MARKET_BASED: {
                "urgency": {"low": 0.6, "medium": 0.8, "high": 0.7, "critical": 0.4},
                "complexity": {"simple": 0.4, "moderate": 0.7, "complex": 0.9, "critical": 0.8},
                "task_type": {"execution": 0.9, "research": 0.8, "monitoring": 0.6},
                "participant_count": {"1-3": 0.4, "4-6": 0.7, "7-10": 0.9, "10+": 0.8},
                "time_constraints": {"low": 0.7, "medium": 0.8, "high": 0.6},
                "resource_constraints": {"abundant": 0.9, "sufficient": 0.7, "limited": 0.4}
            },
            CoordinationMode.SWARM: {
                "urgency": {"low": 0.5, "medium": 0.6, "high": 0.8, "critical": 0.9},
                "complexity": {"simple": 0.6, "moderate": 0.7, "complex": 0.8, "critical": 0.9},
                "task_type": {"emergency": 0.9, "monitoring": 0.8, "research": 0.7},
                "participant_count": {"1-3": 0.3, "4-6": 0.6, "7-10": 0.8, "10+": 0.9},
                "time_constraints": {"low": 0.4, "medium": 0.6, "high": 0.8},
                "resource_constraints": {"abundant": 0.8, "sufficient": 0.6, "limited": 0.7}
            },
            CoordinationMode.HYBRID: {
                "urgency": {"low": 0.7, "medium": 0.8, "high": 0.7, "critical": 0.6},
                "complexity": {"simple": 0.6, "moderate": 0.8, "complex": 0.9, "critical": 0.8},
                "task_type": {"decision": 0.7, "execution": 0.8, "research": 0.9},
                "participant_count": {"1-3": 0.6, "4-6": 0.8, "7-10": 0.9, "10+": 0.8},
                "time_constraints": {"low": 0.8, "medium": 0.8, "high": 0.7},
                "resource_constraints": {"abundant": 0.9, "sufficient": 0.8, "limited": 0.6}
            }
        }
    
    def _is_in_range(self, value: float, range_key: str) -> bool:
        """检查值是否在指定范围内"""
        if range_key == "1-3":
            return 1 <= value <= 3
        elif range_key == "4-6":
            return 4 <= value <= 6
        elif range_key == "7-10":
            return 7 <= value <= 10
        elif range_key == "10+":
            return value > 10
        elif range_key == "low":
            return value < 0.3
        elif range_key == "medium":
            return 0.3 <= value < 0.7
        elif range_key == "high":
            return value >= 0.7
        else:
            return False
    
    def _calculate_time_pressure(self, deadline: datetime) -> float:
        """计算时间压力"""
        if isinstance(deadline, str):
            # 简单的字符串解析
            try:
                deadline = datetime.fromisoformat(deadline)
            except:
                return 0.5  # 默认中等压力
        
        time_remaining = deadline - datetime.now()
        hours_remaining = time_remaining.total_seconds() / 3600
        
        if hours_remaining < 1:
            return 1.0  # 高压力
        elif hours_remaining < 6:
            return 0.8
        elif hours_remaining < 24:
            return 0.6
        elif hours_remaining < 72:
            return 0.4
        else:
            return 0.2  # 低压力
    
    def _calculate_resource_availability(self, resource_constraints: Dict[str, Any]) -> float:
        """计算资源可用性"""
        if not resource_constraints:
            return 0.8  # 默认充足
        
        # 简化的资源可用性计算
        availability_indicators = []
        
        # 计算资源
        computational = resource_constraints.get("computational", 1.0)
        availability_indicators.append(computational)
        
        # 数据访问
        data_access = resource_constraints.get("data_access", 1.0)
        availability_indicators.append(data_access)
        
        # 人力资源
        human_resources = resource_constraints.get("human_resources", 1.0)
        availability_indicators.append(human_resources)
        
        # 外部API
        external_api = resource_constraints.get("external_api", 1.0)
        availability_indicators.append(external_api)
        
        return sum(availability_indicators) / len(availability_indicators)
    
    def _update_usage_statistics(self, mode: CoordinationMode):
        """更新使用统计"""
        performance = self.mode_performance_history[mode]
        performance["usage_count"] += 1
        performance["last_used"] = datetime.now()
    
    def update_performance(
        self,
        mode: CoordinationMode,
        success: bool,
        duration: float,
        failure_reason: Optional[str] = None
    ):
        """
        更新模式性能
        
        Args:
            mode: 协调模式
            success: 是否成功
            duration: 执行时长
            failure_reason: 失败原因
        """
        performance = self.mode_performance_history[mode]
        
        # 更新成功率
        total_count = performance["usage_count"]
        current_success_rate = performance["success_rate"]
        
        if total_count > 0:
            new_success_rate = (
                (current_success_rate * total_count + (1.0 if success else 0.0)) /
                (total_count + 1)
            )
        else:
            new_success_rate = 1.0 if success else 0.0
        
        performance["success_rate"] = new_success_rate
        
        # 更新平均时长
        current_avg_duration = performance["average_duration"]
        if total_count > 0:
            new_avg_duration = (
                (current_avg_duration * total_count + duration) /
                (total_count + 1)
            )
        else:
            new_avg_duration = duration
        
        performance["average_duration"] = new_avg_duration
        
        # 记录失败原因
        if not success and failure_reason:
            performance["failure_reasons"].append({
                "reason": failure_reason,
                "timestamp": datetime.now()
            })
            
            # 只保留最近的10个失败原因
            if len(performance["failure_reasons"]) > 10:
                performance["failure_reasons"] = performance["failure_reasons"][-10:]
    
    def get_mode_recommendations(
        self,
        context: CoordinationContext,
        top_k: int = 3
    ) -> List[Tuple[CoordinationMode, float]]:
        """
        获取模式推荐
        
        Args:
            context: 协调上下文
            top_k: 返回前k个推荐
            
        Returns:
            模式和分数的列表
        """
        mode_scores = self._calculate_mode_scores(context)
        
        # 按分数排序
        sorted_modes = sorted(
            mode_scores.items(),
            key=lambda x: x[1],
            reverse=True
        )
        
        return sorted_modes[:top_k]
    
    def get_selection_statistics(self) -> Dict[str, Any]:
        """获取选择统计信息"""
        if not self.selection_history:
            return {"total_selections": 0}
        
        # 模式使用分布
        mode_distribution = {}
        for record in self.selection_history:
            mode = record["selected_mode"]
            mode_distribution[mode.value] = mode_distribution.get(mode.value, 0) + 1
        
        # 平均选择时间
        avg_selection_time = sum(
            record["selection_duration"] for record in self.selection_history
        ) / len(self.selection_history)
        
        # 最近的选择
        recent_selections = self.selection_history[-10:]
        
        return {
            "total_selections": len(self.selection_history),
            "mode_distribution": mode_distribution,
            "average_selection_time": avg_selection_time,
            "recent_selections": [
                {
                    "timestamp": record["timestamp"].isoformat(),
                    "selected_mode": record["selected_mode"].value,
                    "context_summary": {
                        "task_type": record["context"].task_type,
                        "urgency": record["context"].urgency_level,
                        "complexity": record["context"].complexity
                    }
                }
                for record in recent_selections
            ],
            "performance_history": {
                mode.value: {
                    "success_rate": perf["success_rate"],
                    "usage_count": perf["usage_count"],
                    "average_duration": perf["average_duration"]
                }
                for mode, perf in self.mode_performance_history.items()
            }
        }
    
    def reset_performance_history(self):
        """重置性能历史"""
        for mode in CoordinationMode:
            self.mode_performance_history[mode] = {
                "success_rate": 0.5,
                "average_duration": 3600.0,
                "usage_count": 0,
                "last_used": None,
                "failure_reasons": []
            }
        
        self.selection_history.clear()